home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / lfsrecov / dirlog.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-16  |  13.3 KB  |  502 lines

  1. /* 
  2.  * dirlog.c --
  3.  *
  4.  *    Directory change log manipulation routines for the lfsrecov program.
  5.  *
  6.  * Copyright 1991 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that this copyright
  10.  * notice appears in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/lib/forms/RCS/proto.c,v 1.5 91/02/09 13:24:44 ouster Exp $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include "lfslib.h"
  21. #include <stdio.h>
  22. #include <sys/types.h>
  23. #include <sys/file.h>
  24. #include <option.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <alloca.h>
  28. #include <bstring.h>
  29. #include <unistd.h>
  30. #include <bit.h>
  31. #include <time.h>
  32. #include <sys/time.h>
  33. #include <assert.h>
  34. #include <hash.h>
  35. #include <libc.h>
  36.  
  37. #include "lfsrecov.h"
  38. #include "dirlog.h"
  39. #include "desc.h"
  40. #include "fileop.h"
  41. #include "usage.h"
  42.  
  43. /*
  44.  * startEntryHashTable -
  45.  * Hash table data structures used to record the addresses of log start
  46.  * entries for future reference when the end entry is found.
  47.  * startEntryHashTableInit - 
  48.  * Set to TRUE when the hash table startEntryHashTable has been initialized.
  49.  */
  50. static Hash_Table startEntryHashTable;
  51. static Boolean    startEntryHashTableInit = FALSE;
  52.  
  53. /*
  54.  *----------------------------------------------------------------------
  55.  *
  56.  * RecordLogEntryStart --
  57.  *
  58.  *    Record the address of an FSDM_LOG_START_ENTRY that is not 
  59.  *    also the END entry so we can match it will the END entry when
  60.  *    we encounter it.
  61.  *
  62.  * Results:
  63.  *    None.
  64.  *
  65.  * Side effects:
  66.  *    An entry is made in the startEntryHashTable.
  67.  *
  68.  *----------------------------------------------------------------------
  69.  */
  70.  
  71. void
  72. RecordLogEntryStart(entryPtr, addr)
  73.     LfsDirOpLogEntry *entryPtr;    /* Log entry with start bit to be recorded. */
  74.     int             addr;    /* Disk address of log entry. */
  75. {
  76.     Hash_Entry *hentryPtr;
  77.     Boolean new;
  78.  
  79.     assert((entryPtr->hdr.opFlags & FSDM_LOG_START_ENTRY) &&
  80.             !(entryPtr->hdr.opFlags & FSDM_LOG_END_ENTRY));
  81.  
  82.     if (!startEntryHashTableInit) {
  83.     Hash_InitTable(&startEntryHashTable, 0, HASH_ONE_WORD_KEYS);
  84.     startEntryHashTableInit = TRUE;
  85.     } 
  86.  
  87.     hentryPtr = Hash_CreateEntry(&startEntryHashTable, 
  88.             (Address) entryPtr->hdr.logSeqNum, &new);
  89.     if (!new) {
  90.     panic("LogStart entry %d already in has table\n", 
  91.             entryPtr->hdr.logSeqNum);
  92.     }
  93.     Hash_SetValue(hentryPtr, (ClientData)addr);
  94.     return;
  95. }
  96.  
  97.  
  98. /*
  99.  *----------------------------------------------------------------------
  100.  *
  101.  * FindStartEntryAddr --
  102.  *
  103.  *    Find the address of the START entry of the specified log
  104.  *    sequence number. This routine is used to find the range of
  105.  *    blocks between a START and END entry.
  106.  *
  107.  * Results:
  108.  *    TRUE if the start entry's address is found. FALSE if no entry
  109.  *     was record under that seqence number.
  110.  *
  111.  * Side effects:
  112.  *
  113.  *----------------------------------------------------------------------
  114.  */
  115.  
  116. Boolean
  117. FindStartEntryAddr(logSeqNum, addrPtr)
  118.     int        logSeqNum;    /* Log seq number of entry we wish to lookup.*/
  119.     int        *addrPtr;    /* OUT: Address of start entry record. */
  120. {
  121.  
  122.     Hash_Entry *hentryPtr;
  123.  
  124.     if (!startEntryHashTableInit) {
  125.     Hash_InitTable(&startEntryHashTable, 0, HASH_ONE_WORD_KEYS);
  126.     startEntryHashTableInit = TRUE;
  127.     } 
  128.     hentryPtr = Hash_FindEntry(&startEntryHashTable, (Address)logSeqNum);
  129.     if (hentryPtr == (Hash_Entry *) NULL) {
  130.     return FALSE;
  131.     }
  132.     (*addrPtr) = (int) Hash_GetValue(hentryPtr);
  133.     return TRUE;
  134. }
  135.  
  136.  
  137. /*
  138.  *----------------------------------------------------------------------
  139.  *
  140.  * DirOpFlagsToString --
  141.  *
  142.  *    Convert a directory change opcode into a printable strings.
  143.  *
  144.  * Results:
  145.  *    A printable string.
  146.  *
  147.  * Side effects:
  148.  *    None.
  149.  *
  150.  *----------------------------------------------------------------------
  151.  */
  152.  
  153. char *
  154. DirOpFlagsToString(opFlags)
  155.     int opFlags;
  156. {
  157.     int op = opFlags & FSDM_LOG_OP_MASK;
  158.     char buffer[128];
  159.     static char *opcodes[] = {"UNKNOWN", "CREATE", "UNLINK", "LINK", 
  160.             "RENAME_DELETE", "RENAME_LINK", "RENAME_UNLINK", 
  161.             "UNKNOWN"};
  162.     if ((op < 0) || (op >= sizeof(opcodes)/sizeof(opcodes[0]))) {
  163.     op = sizeof(opcodes)/sizeof(opcodes[0])-1;
  164.     }
  165.     strcpy(buffer,opcodes[op]);
  166.     if (opFlags & FSDM_LOG_STILL_OPEN) {
  167.     strcat(buffer, "-OPEN");
  168.     opFlags ^= FSDM_LOG_STILL_OPEN;
  169.     }
  170.     if (opFlags & FSDM_LOG_START_ENTRY) {
  171.     strcat(buffer, "-START");
  172.     opFlags ^= FSDM_LOG_START_ENTRY;
  173.     }
  174.     if (opFlags & FSDM_LOG_END_ENTRY) {
  175.     strcat(buffer, "-END");
  176.     opFlags ^= FSDM_LOG_END_ENTRY;
  177.     }
  178.     if (opFlags & FSDM_LOG_IS_DIRECTORY) {
  179.     strcat(buffer, "-DIR");
  180.     opFlags ^= FSDM_LOG_IS_DIRECTORY;
  181.     }
  182.     if (opFlags & ~FSDM_LOG_OP_MASK) {
  183.     strcat(buffer, "-UNKNOWN");
  184.     }
  185.     return buffer;
  186.  
  187. }
  188.  
  189.  
  190. /*
  191.  *----------------------------------------------------------------------
  192.  *
  193.  * ShowDirLogBlock --
  194.  *
  195.  *    Print the contents of a directory log block.
  196.  *
  197.  * Results:
  198.  *    None
  199.  *
  200.  * Side effects:
  201.  *    None.
  202.  *
  203.  *----------------------------------------------------------------------
  204.  */
  205.  
  206.  
  207. extern void
  208. ShowDirLogBlock(hdrPtr, addr)
  209.     LfsDirOpLogBlockHdr *hdrPtr;  /* Header of log block. */
  210.     int addr;              /* Address of log block. */
  211. {
  212.     LfsDirOpLogEntry *entryPtr, *limitPtr;
  213.  
  214.     limitPtr = (LfsDirOpLogEntry *) (((char *) hdrPtr) + hdrPtr->size);
  215.     entryPtr = (LfsDirOpLogEntry *) (hdrPtr+1);
  216.     while (entryPtr < limitPtr) {
  217.     entryPtr->dirEntry.fileName[entryPtr->dirEntry.nameLength] = '\0';
  218.     printf("Addr %d LogSeqNum %d %s %d \"%s\" links %d in %d at %d\n",
  219.         addr,
  220.         entryPtr->hdr.logSeqNum, 
  221.         DirOpFlagsToString(entryPtr->hdr.opFlags), 
  222.         entryPtr->dirEntry.fileNumber, 
  223.         entryPtr->dirEntry.fileName,
  224.         entryPtr->hdr.linkCount,
  225.         entryPtr->hdr.dirFileNumber,
  226.         entryPtr->hdr.dirOffset);
  227.     entryPtr = (LfsDirOpLogEntry *) 
  228.              (((char *)entryPtr) + LFS_DIR_OP_LOG_ENTRY_SIZE(entryPtr));
  229.     }
  230.  
  231. }
  232.  
  233.  
  234. /*
  235.  *----------------------------------------------------------------------
  236.  *
  237.  * RecovDirLogBlock --
  238.  *
  239.  *    Process recovery of the directory change log.
  240.  *
  241.  * Results:
  242.  *    None.
  243.  *
  244.  * Side effects:
  245.  *    None.
  246.  *
  247.  *----------------------------------------------------------------------
  248.  */
  249. void
  250. RecovDirLogBlock(hdrPtr, addr, pass)
  251.     LfsDirOpLogBlockHdr *hdrPtr;    /* Header of log block. */
  252.     int addr;                /* Address of log block. */
  253.     enum Pass pass;            /* Pass of recovery. */
  254. {
  255.     int    fileNumber;
  256.     LfsDirOpLogEntry *entryPtr, *limitPtr;
  257.  
  258.  
  259.     limitPtr = (LfsDirOpLogEntry *) (((char *) hdrPtr) + hdrPtr->size);
  260.     entryPtr = (LfsDirOpLogEntry *) (hdrPtr+1);
  261.     /*
  262.      * Exmaine each enry in the log blocks. 
  263.      */
  264.     while (entryPtr < limitPtr) {
  265.     int    op;
  266.     op = entryPtr->hdr.opFlags & FSDM_LOG_OP_MASK;
  267.     fileNumber = entryPtr->dirEntry.fileNumber;
  268.     if (pass == PASS1) { 
  269.         stats.numDirLogEntries++;
  270.     }
  271.     switch (op) {
  272.         case FSDM_LOG_RENAME_DELETE:
  273.         case FSDM_LOG_UNLINK: {
  274.         if (pass == PASS1) {
  275.             if (entryPtr->hdr.linkCount == 0) {
  276.             if((entryPtr->hdr.opFlags & FSDM_LOG_STILL_OPEN) == 0) {
  277.                 stats.numDirLogDelete++;
  278.                 RecordNewDesc(fileNumber, addr, 
  279.                     (LfsFileDescriptor *) NIL);
  280.             } else {
  281.                 stats.numDirLogDeleteOpen++;
  282.                 RecordUnrefDesc(fileNumber, 
  283.                     entryPtr->hdr.dirFileNumber,
  284.                     &entryPtr->dirEntry);
  285.             }
  286.             } else {
  287.             stats.numDirLogUnlink++;
  288.             }
  289.         } else {
  290.             /*
  291.              * Recover the operation. 
  292.              */
  293.             RecovDirLogEntry(entryPtr, addr);
  294.         }
  295.         break;
  296.         }
  297.         case FSDM_LOG_CREATE:
  298.         case FSDM_LOG_RENAME_UNLINK:
  299.         case FSDM_LOG_LINK:
  300.         case FSDM_LOG_RENAME_LINK:
  301.         if (pass == PASS2) {
  302.             stats.numDirLogCreate++;
  303.             RecovDirLogEntry(entryPtr, addr);
  304.         }
  305.         break;
  306.         default:
  307.         fprintf(stderr,"%s:Unknown log entry 0x%x\n", deviceName,
  308.                 entryPtr->hdr.opFlags);
  309.         break;
  310.     }
  311.     entryPtr = (LfsDirOpLogEntry *) 
  312.              (((char *)entryPtr) + LFS_DIR_OP_LOG_ENTRY_SIZE(entryPtr));
  313.     }
  314.  
  315. }
  316.  
  317. /*
  318.  *----------------------------------------------------------------------
  319.  *
  320.  * RecovDirLogEntry --
  321.  *
  322.  *    Recover changes record in a directory log entry.
  323.  *
  324.  * Results:
  325.  *    None.
  326.  *
  327.  * Side effects:
  328.  *    None.
  329.  *
  330.  *----------------------------------------------------------------------
  331.  */
  332. void
  333. RecovDirLogEntry(entryPtr, addr)
  334.     LfsDirOpLogEntry *entryPtr;
  335.     int             addr;
  336. {
  337.     enum LogStatus    dirBlockStatus, descStatus;
  338.     int    logStartAddr;
  339.     Boolean  mayExist;
  340.     ReturnStatus status;
  341.     int    op = entryPtr->hdr.opFlags & FSDM_LOG_OP_MASK;
  342.  
  343.     if ((entryPtr->hdr.opFlags & FSDM_LOG_START_ENTRY) &&
  344.         !(entryPtr->hdr.opFlags & FSDM_LOG_END_ENTRY)) {
  345.     /*
  346.      * Record any START entry that wasn't finished. It will be
  347.      * processed when we find the END entry or the end-of-log.
  348.      */
  349.     stats.numDirLogWithoutEnd++;
  350.     RecordLogEntryStart(entryPtr, addr);
  351.     return;
  352.     } 
  353.     /*
  354.      * Find the status of the operands (the file and the directory).
  355.      */
  356.     logStartAddr = addr;
  357.     if(!(entryPtr->hdr.opFlags & FSDM_LOG_START_ENTRY)) {
  358.     /*
  359.      * Find address of start entry.
  360.      */
  361.     if (!FindStartEntryAddr(entryPtr->hdr.logSeqNum, &logStartAddr)) {
  362.         fprintf(stderr, "No starting log entry for %d\n", entryPtr->hdr.logSeqNum);
  363.         logStartAddr = addr;
  364.     }
  365.     }
  366.  
  367.     dirBlockStatus = DirBlockStatus( entryPtr->hdr.dirFileNumber, 
  368.                   entryPtr->hdr.dirOffset, logStartAddr,
  369.                   addr); 
  370.     descStatus = DescStatus(entryPtr->dirEntry.fileNumber, logStartAddr, addr);
  371.  
  372.     mayExist = (dirBlockStatus == UNKNOWN);
  373.     if (descStatus == FORWARD) { 
  374.     /*
  375.      * The inode made it out, all we need to do is make sure that
  376.      * the directory change did to.
  377.      */
  378.     switch (dirBlockStatus) {
  379.         case FORWARD:
  380.         /*
  381.          * Both the desc and the directory block made it out. The are 
  382.          * no changes except moving forward the descriptor map.
  383.          */
  384.         stats.dirLogBothForward++;
  385.         break;
  386.         case BACKWARD: 
  387.         case UNKNOWN:
  388.         /*
  389.          * The desc made it out but the directory block didn't.  
  390.          * Correct directory entry.
  391.          */
  392.         stats.dirLogDirBlockBackward++;
  393.         if ((op == FSDM_LOG_CREATE) || (op == FSDM_LOG_LINK) ||
  394.             (op == FSDM_LOG_RENAME_LINK)) { 
  395.             status = AddEntryToDirectory(entryPtr->hdr.dirFileNumber, 
  396.             entryPtr->hdr.dirOffset, &entryPtr->dirEntry, 
  397.             (entryPtr->hdr.opFlags & FSDM_LOG_IS_DIRECTORY),
  398.             mayExist);
  399.             if (status == FS_FILE_NOT_FOUND) {
  400.             status = CreateLostDirectory(
  401.                     entryPtr->hdr.dirFileNumber);
  402.             if (status == SUCCESS) {
  403.                 status = AddEntryToDirectory(
  404.                     entryPtr->hdr.dirFileNumber, 
  405.                     entryPtr->hdr.dirOffset, 
  406.                     &entryPtr->dirEntry, 
  407.                     (entryPtr->hdr.opFlags & FSDM_LOG_IS_DIRECTORY),
  408.                     FALSE);
  409.                 }
  410.  
  411.             }
  412.             if (status != SUCCESS) {
  413.             fprintf(stderr,"Can't rollforward CREATE\n"); 
  414.             exit(1);
  415.             }
  416.  
  417.  
  418.         } else if ((op == FSDM_LOG_UNLINK) || 
  419.                    (op == FSDM_LOG_RENAME_UNLINK)) {
  420.             RemovedEntryFromDirectory( entryPtr->hdr.dirFileNumber, 
  421.               entryPtr->hdr.dirOffset, &entryPtr->dirEntry, 
  422.               (entryPtr->hdr.opFlags & FSDM_LOG_IS_DIRECTORY),
  423.               TRUE);
  424.         }
  425.         break;
  426.         default: 
  427.         panic("Unknown dirBlockStatus status %d\n", dirBlockStatus);
  428.         break;
  429.      }
  430.      return;
  431.     } 
  432.     /*
  433.      * The descriptor may or may not have made it out. We can roll forward 
  434.      * everything but creates.
  435.      */
  436.     if (op == FSDM_LOG_CREATE) {
  437.       /*
  438.        * We assume that an unknown descriptor really means it made
  439.        * it out. 
  440.        */
  441.       if (descStatus == BACKWARD) { 
  442.           stats.dirLogBothBackwardCreate++;
  443.           RecordLostCreate(entryPtr->hdr.dirFileNumber,&entryPtr->dirEntry);
  444.           if ((dirBlockStatus == FORWARD) || (dirBlockStatus == UNKNOWN)) {
  445.           RemovedEntryFromDirectory( entryPtr->hdr.dirFileNumber, 
  446.              entryPtr->hdr.dirOffset, &entryPtr->dirEntry, 
  447.              (entryPtr->hdr.opFlags & FSDM_LOG_IS_DIRECTORY),TRUE);
  448.           } 
  449.       } else if (descStatus == UNKNOWN) {
  450.           if ((dirBlockStatus == BACKWARD) || (dirBlockStatus == UNKNOWN)) {
  451.         AddEntryToDirectory(entryPtr->hdr.dirFileNumber, 
  452.                 entryPtr->hdr.dirOffset, &entryPtr->dirEntry,
  453.                 (entryPtr->hdr.opFlags & FSDM_LOG_IS_DIRECTORY),
  454.                 (dirBlockStatus == UNKNOWN));
  455.           }
  456.       }
  457.       return;
  458.     } 
  459.     /*
  460.      * It is some other operation that changed the link count.  Just
  461.      * update the link count to reflect the change.
  462.      */
  463.     UpdateDescLinkCount(OP_ABS, entryPtr->dirEntry.fileNumber, 
  464.             entryPtr->hdr.linkCount);
  465.     if ((dirBlockStatus == BACKWARD) || (dirBlockStatus == UNKNOWN)) {
  466.     stats.dirLogBothBackward++;
  467.     if ((op == FSDM_LOG_LINK) ||
  468.         (op == FSDM_LOG_RENAME_LINK)) {
  469.         status = AddEntryToDirectory(entryPtr->hdr.dirFileNumber, 
  470.             entryPtr->hdr.dirOffset, &entryPtr->dirEntry, 
  471.             (entryPtr->hdr.opFlags & FSDM_LOG_IS_DIRECTORY), mayExist);
  472.         if (status == FS_FILE_NOT_FOUND) {
  473.             status = CreateLostDirectory(
  474.                     entryPtr->hdr.dirFileNumber);
  475.             if (status == SUCCESS) {
  476.             status = AddEntryToDirectory(
  477.                     entryPtr->hdr.dirFileNumber, 
  478.                     entryPtr->hdr.dirOffset, 
  479.                     &entryPtr->dirEntry, 
  480.                     (entryPtr->hdr.opFlags & FSDM_LOG_IS_DIRECTORY),
  481.                     mayExist);
  482.             }
  483.  
  484.         }
  485.         if (status != SUCCESS) {
  486.             fprintf(stderr,"Can't rollforward change\n");
  487.             exit(1);
  488.         }
  489.     } else if ((op == FSDM_LOG_UNLINK) ||
  490.            (op == FSDM_LOG_RENAME_UNLINK)) {
  491.         RemovedEntryFromDirectory(entryPtr->hdr.dirFileNumber, 
  492.                  entryPtr->hdr.dirOffset, &entryPtr->dirEntry, 
  493.                  (entryPtr->hdr.opFlags & FSDM_LOG_IS_DIRECTORY),
  494.                  TRUE);
  495.        }
  496.     }
  497. }
  498.  
  499.  
  500.  
  501.  
  502.